// Netris. A free, open source Tetris(tm) clone
// Copyright (C) 2005  Parez Timothy
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

using System;
using System.Text;
using System.Drawing;
using SdlDotNet;
using SdlDotNet.Sprites;

namespace Beaglebits.Games.Netris
{
    public class GameField
    {
        //Constant values
        public static int Width = 10;
        public static int Height = 20;
        public static Bitmap[] SquareImages = new Bitmap[7];
        public static Surface GameFieldSurface;
        //public static Surface PreviewSurface;

        //Private fields
        private static Color backgroundColor = Color.White;
        private static Square[,] gameFieldSquares = new Square[GameField.Width, GameField.Height];
        private static int[] gameFieldBits = new int[GameField.Height];

        internal static int score;
        internal static int lines;
        internal static int level;
        internal static int drops;
        
        private static TextSprite scoreSprite; //new TextSprite("...one", f2, c2, new Point(5, 35))
        private static TextSprite linesSprite;
        private static TextSprite levelSprite;
        
        private static TextSprite[] helpSprites;

        public static int Score
        {
            get
            {
                return GameField.score;
            }
        }

        public static int Lines
        {
            get
            {
                return GameField.lines;
            }
        }

        public static int Level
        {
            get
            {
                return GameField.level;
            }
        }

        public static Color BackgroundColor
        {
            get
            {
                return GameField.backgroundColor;
            }
            set
            {
                GameField.backgroundColor = value;
                GameField.GameFieldSurface.Fill(GameField.BackgroundColor);
            }
        }

        public static bool IsEmpty(int X, int Y)
        {
            /* Simple test: return (GameField.gameFieldSquares[X, Y] == null);
             * Instead we use a much faster method, using bitwise comparisons */
  
                //Check if X or Y is beyond the gamefield
                if ((X < 0 || X >= GameField.Width) || (Y < 0 || Y >= GameField.Height))
                {
                    return false;
                }
                else
                {

                    // The easiest way to calculate powers of 2 is just to shift the bits to the left 
                    if ((GameField.gameFieldBits[Y] & (1 << X)) > 0)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
        }

        public static int CheckLines()
        {
            int y;
            int linesChecked = 0;

            //Set y to the height minus 1 (array)
             y = GameField.Height - 1;

            //While we aren't at the top
            while (y > 0)
            {
            	//While the lines aren't empty
                if (GameField.gameFieldBits[y] == 0x00)
                {
                	//This is an empty line, no blocks above this line
                    return linesChecked;
                }
                else
                {
                	//If this is a full line
                    if (gameFieldBits[y] == 1023) //Full line in case of 16 width = 0xFFFF
                    {
                        //Increment linexChecked
                        linesChecked++;
    					
                        //Hide all squares of the empty line
                        for (int x = 0; x < GameField.Width; x++)
                        {
                        	GameField.gameFieldSquares[x,y].Hide(GameField.GameFieldSurface);
                        }

                        //Move all the next lines (above this one) down
                        for (int i = y; i >= 0; i--)
                        {
                            //If the current line is not the first of the gamefield, copy the one above
                            if (i > 0)
                            {
                                GameField.gameFieldBits[i] = GameField.gameFieldBits[i - 1];

                                //Copy each of the squares from the line above
                                for (int x = 0; x < GameField.Width; x++)
                                {
                                    //Copy the squares from the line above to this one
                                	GameField.gameFieldSquares[x, i] = GameField.gameFieldSquares[x, i - 1];
                                	
                                    if (gameFieldSquares[x,i] != null)
                                    {
                                    	//Hide the square at it's current position
                                    	GameField.gameFieldSquares[x,i].Hide(GameField.GameFieldSurface);
                                    	
                                        //Update the location property of the square
                                        GameField.gameFieldSquares[x, i].Position = new Point(gameFieldSquares[x, i].Position.X, gameFieldSquares[x, i].Position.Y + GameField.SquareImages[0].Width);
                                        
                                        //Show the square at it's new position
                                        GameField.gameFieldSquares[x ,i].Show(GameField.GameFieldSurface);
                                        
                                    }
                                }
                            }
                            else
                            {
                                //If the line is the first line of the GameField just clear it
                                GameField.gameFieldBits[i] = 0x00;

                                for (int x = 0; x < GameField.Width; x++)
                                {                     
                                   GameField.gameFieldSquares[x, i] = null;                                   
                                }
                            }
                        }            
                    }
                    else
                    {
                        y--; //Only move up a line if the current one isn't full
                    }                    
                }
            }
                      
            //Return the number of checked lines
            return linesChecked;
        }

        public static bool StopSquare(Square Sqr, int X, int Y)
        {
            try
            {
                GameField.gameFieldBits[Y] = gameFieldBits[Y] | (1 << X);
                GameField.gameFieldSquares[X, Y] = Sqr;
                return true;
            }
            catch
            {
                return false;
            }
        }
        
        public static void UpdateScoreView()
        {
        	
        	GameField.scoreSprite.Text = String.Concat("Score: ",GameField.score);
        	GameField.GameFieldSurface.Fill(GameField.scoreSprite.Rectangle,GameField.backgroundColor);
    		GameField.GameFieldSurface.Blit(GameField.scoreSprite.Surface, GameField.scoreSprite.Position);
    		
    		GameField.linesSprite.Text = String.Concat("Lines: ", GameField.lines);
    		GameField.GameFieldSurface.Fill(GameField.linesSprite.Rectangle,GameField.backgroundColor);
        	GameField.GameFieldSurface.Blit(GameField.linesSprite.Surface, GameField.linesSprite.Position);
        	
        	GameField.levelSprite.Text = String.Concat("Level: ", GameField.level);
        	GameField.GameFieldSurface.Fill(GameField.levelSprite.Rectangle,GameField.backgroundColor);
        	GameField.GameFieldSurface.Blit(GameField.levelSprite.Surface, GameField.levelSprite.Position);   
        	
        }
         
        public static void Clear()
        {
        	//Reset the game elements
        	GameField.gameFieldSquares = new Square[GameField.Width, GameField.Height];
            GameField.gameFieldBits = new int[GameField.Height];
            GameField.score = 0;
            GameField.lines = 0;
            GameField.level = 0;
            GameField.drops = 0;
        	
        	//Fill the entire surface
        	GameField.GameFieldSurface.Fill(GameField.backgroundColor);
        	
        	//Draw a line next to the field //TODO: Use a real line instead of a Rectangle
        	GameField.GameFieldSurface.DrawBox(new Rectangle(-1,-1,(GameField.SquareImages[0].Width * GameField.Width) + 1,(GameField.SquareImages[0].Height * GameField.Height) + 1),Color.White);

        	GameField.UpdateScoreView();
        	
        	for (int i = 0; i < GameField.helpSprites.Length;i++)
        	{
        		GameField.GameFieldSurface.Fill(GameField.helpSprites[i].Rectangle,GameField.backgroundColor);
        		GameField.GameFieldSurface.Blit(GameField.helpSprites[i].Surface, GameField.helpSprites[i].Position);
        	}
        	
        	//Required because of update to SDL.NET 4.x
        	GameField.GameFieldSurface.Update();
        }
        
        /// <summary>
        /// Needs to be called before starting the game
        /// </summary>
        public static void Init(string FontPath)
        {
            //Position
            int x = GameField.SquareImages[0].Width * GameField.Width + 10;
            int y = 130;
            
            //Sprite number
            int i  = 0;

            //Create a new Font instance
            SdlDotNet.Font textFont = new SdlDotNet.Font(FontPath, 16);
        	
            //Score Text
            GameField.scoreSprite = new TextSprite("Score: 0", textFont, Color.White, new Point(x, y += 20));
            GameField.linesSprite = new TextSprite("Lines: 0", textFont, Color.White, new Point(x, y += 20));
            GameField.levelSprite = new TextSprite("Lines: 0", textFont, Color.White, new Point(x, y += 20));


            //Create a new Font instance
            textFont = new SdlDotNet.Font(FontPath, 14);

        	//Help Text
            GameField.helpSprites = new TextSprite[12];
            GameField.helpSprites[i++] = new TextSprite("F1 - Start game", textFont, Color.White, new Point(x, y += 50));
            GameField.helpSprites[i++] = new TextSprite("F2 - Stop game", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("F3 - Pause game", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("Esc - Main menu", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("S - Toggle Music", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("------------------------------", textFont, Color.White, new Point(x, y += 30));
            GameField.helpSprites[i++] = new TextSprite("Up: Rotate block", textFont, Color.White, new Point(x, y += 30));
            GameField.helpSprites[i++] = new TextSprite("Left: Move block left", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("Right: Move block right", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("Down: Move block down", textFont, Color.White, new Point(x, y += 20));
            GameField.helpSprites[i++] = new TextSprite("Space: Drop block", textFont, Color.White, new Point(x, y += 20));

            //Create a new Font instance
            textFont = new SdlDotNet.Font(FontPath, 9);

			GameField.helpSprites[i++] = new TextSprite("http://www.netris.be",textFont,Color.White, new Point(x, 625));
        }
    }
}
